package com.lry.jvm.instructions.refrences;

import com.lry.jvm.instructions.base.BytecodeReader;
import com.lry.jvm.instructions.base.Index16Instruction;
import com.lry.jvm.instructions.base.MethodInvoke;
import com.lry.jvm.rtda.Frame;
import com.lry.jvm.rtda.JObject;
import com.lry.jvm.rtda.heap.*;
import com.lry.jvm.util.Util;

public class invokeinterface   extends Index16Instruction{

    private int index;

    @Override
    public byte getOpCode() {
        return (byte) 0xb9;
    }

    @Override
    public void fetchOperands(BytecodeReader reader) {
        index = reader.read16();
        reader.read8();
        reader.read8();
    }

    @Override
    public void execute(Frame frame) {
        RuntimeConstantPool rcp = frame.getMethod().getJClass().getConstantPool();
        InterfaceMethodRef methodRef = (InterfaceMethodRef) rcp.getConstant(index);
        JMethod resolvedMethod = methodRef.resolvedInterfaceMethod();
        //校验接口方法
        if (resolvedMethod.isStatic() || resolvedMethod.isPrivate()) {
            Util.panic("java.lang.IncompatibleClassChangeError");
        }

        JObject ref = frame.getOperandStack().getRefFromTop(resolvedMethod.getArgsSlotCount()-1);
        if (ref == null) {
            Util.panic("java.lang.NullPointerException");
        }
        if (!ref.getJClass().isImplements(methodRef.resolvedClass())) {
            Util.panic("java.lang.IncompatibleClassChangeError");
        }

        //拿实现类的方法去执行
        resolvedMethod = MethodLookup.lookupMethodInClass(ref.getJClass(),methodRef.getName(),methodRef.getDescriptor());
        if(null==resolvedMethod || resolvedMethod.getJClass().isAbstract()){
            Util.panic("java.lang.AbstractMethodError");
        }

        if(!resolvedMethod.isPublic()){
            Util.panic("java.lang.IllegalAccessError");
        }
        MethodInvoke.invokeMethod(frame,resolvedMethod);

    }
}
